package cn.sylinx.horm.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import cn.sylinx.horm.exception.HORMException;
import cn.sylinx.horm.proxy.command.CommandMethodMetadata;
import cn.sylinx.horm.proxy.command.invoker.CommandInvokerManager;
import cn.sylinx.horm.proxy.mapper.MapperMethodMetadata;
import cn.sylinx.horm.proxy.mapper.invoker.MapperInvokerManager;
import cn.sylinx.horm.util.Tuple;

public class ProxyObject<T> implements InvocationHandler {

    private Class<T> interfaceClass;
    private ProxyType proxyType;

    public ProxyObject() {

    }

    public ProxyObject(Class<T> interfaceClass, ProxyType proxyType) {
        this.interfaceClass = interfaceClass;
        this.proxyType = proxyType;
    }

    public Class<T> getInterfaceClass() {
        return interfaceClass;
    }

    public void setInterfaceClass(Class<T> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }

    public ProxyType getProxyType() {
        return proxyType;
    }

    public void setProxyType(ProxyType proxyType) {
        this.proxyType = proxyType;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (ProxyType.command == proxyType) {
            return invokeCommand(proxy, method, args);
        }

        if (ProxyType.mapper == proxyType) {
            return invokeMapper(proxy, method, args);
        }

        // 不可能到这。。。
        throw new HORMException("invalid proxy type");
    }

    private Object invokeMapper(Object proxy, Method method, Object[] args) throws Throwable {
        MapperMethodMetadata metadata = MapperMethodMetadata.get(getInterfaceClass(), method);
        // Tuple[0]:查询参数, Tuple[1]:pageNumber, Tuple[2]:pageSize
        Tuple tuple = metadata.resove(args);
        return invokerMapperInner(metadata, tuple);
    }

    private Object invokerMapperInner(MapperMethodMetadata metadata, Tuple tuple) {
        return MapperInvokerManager.getBy(metadata).invoke(metadata, tuple);
    }

    private Object invokeCommand(Object proxy, Method method, Object[] args) throws Throwable {
        CommandMethodMetadata metadata = CommandMethodMetadata.get(getInterfaceClass(), method);
        // Tuple[0]:查询参数, Tuple[1]:pageNumber, Tuple[2]:pageSize,Tuple[3]:datasource
        Tuple tuple = metadata.resove(args);
        return invokeCommandInner(metadata, tuple);
    }

    private Object invokeCommandInner(CommandMethodMetadata metadata, Tuple tuple) {
        return CommandInvokerManager.getBy(metadata).invoke(metadata, tuple);
    }
}
